// Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Windows.Forms;
using System.Collections.Generic;
using Microsoft.WindowsAPICodePack.DirectX.Direct2D1;
using Microsoft.WindowsAPICodePack.DirectX.DirectWrite;
using Microsoft.WindowsAPICodePack.DirectX.WindowsImagingComponent;

namespace D2DPaint
{
    enum Shape
    {
        None,
        Line,
        Bitmap,
        Rectangle,
        RoundedRectangle,
        Ellipse,
        Text,
        Geometry
    }
    public partial class Pain2DForm : Form
    {
        internal List<Brush> brushes = new List<Brush>();
        internal int currentBrushIndex = -1;

        private Point2F startPoint;
        private Point2F endPoint;
        private BrushDialog brushDialog = null;
        private List<DrawingShape> drawingShapes = new List<DrawingShape>();
        private D2DBitmap currentBitmap;
        private TextLayout currentTextLayout;
        private Shape currentShapeType = Shape.None;
        private DrawingShape currentShape = null;
        private bool fill = false;


        internal D2DFactory d2dFactory;
        internal ImagingFactory wicFactory;
        internal DWriteFactory dwriteFactory;
        internal HwndRenderTarget renderTarget;

        private bool isDrawing = false;
        private bool isDragging = false;

        float currentStrokeSize = 2;
        float currentTransparency = 1;

        private readonly ColorF WhiteBackgroundColor = new ColorF(1, 1, 1, 0);

        public Pain2DForm()
        {
            InitializeComponent();
            strokeWidths.SelectedItem = "2";
            traparencyList.SelectedItem = "1.0";
        }

        void renderControl_SizeChanged(object sender, EventArgs e)
        {
            if (renderTarget != null)
            {
                // Resize the render targrt to the actual host size
                SizeU size = new SizeU((uint)renderControl.ClientSize.Width, (uint)renderControl.ClientSize.Height);
                renderTarget.Resize(size);
            }
        }

        /// <summary>
        /// This method creates the render target and all associated D2D and DWrite resources
        /// </summary>
        void CreateDeviceResources()
        {
            // Only calls if resources have not been initialize before
            if (renderTarget == null)
            {
                // Create the render target
                SizeU size = new SizeU((uint)renderControl.ClientSize.Width, (uint)renderControl.ClientSize.Height);
                RenderTargetProperties props = new RenderTargetProperties();
                HwndRenderTargetProperties hwndProps = new HwndRenderTargetProperties(renderControl.Handle, size, PresentOptions.None);
                renderTarget = d2dFactory.CreateHwndRenderTarget(props, hwndProps);

                // A black brush to be used for drawing text
                brushes.Add(renderTarget.CreateSolidColorBrush(new ColorF(0, 0, 0, 1)));
                currentBrushIndex = 0;
            }
        }

        private void RenderScene()
        {
            CreateDeviceResources();

            if (renderTarget.IsOccluded)
                return;

            renderTarget.BeginDraw();

            renderTarget.Clear(WhiteBackgroundColor);

            foreach (DrawingShape shape in drawingShapes)
            {
                shape.Draw(renderTarget);
            }

            renderTarget.EndDraw();

        }


        private void setBrush_Click(object sender, EventArgs e)
        {
            if (brushDialog == null || brushDialog.IsDisposed)
                brushDialog = new BrushDialog(this);

            brushDialog.Show();
        }

        private void drawLine_Click(object sender, EventArgs e)
        {
            if (isDrawing)
                return;
            
            this.Cursor = Cursors.Cross;
            currentShapeType = Shape.Line;
            isDrawing = true;
        }

        private void renderControl_Load(object sender, EventArgs e)
        {
            // Create the D2D Factory
            d2dFactory = D2DFactory.CreateFactory(D2DFactoryType.SingleThreaded);

            // Create the DWrite Factory
            dwriteFactory = DWriteFactory.CreateFactory();

            // Create the WIC Factory
            wicFactory = new ImagingFactory();
            
            renderControl.Render = RenderScene;
        }

        private void drawBitmap_Click(object sender, EventArgs e)
        {
            if (isDrawing)
                return;

            OpenFileDialog dialog = new OpenFileDialog();
            dialog.DefaultExt = "*.jpg;*.png";
            dialog.ShowDialog();
            string filename = dialog.FileName;
            currentBitmap = BitmapUtilities.LoadBitmapFromFile(renderTarget, wicFactory, filename);

            this.Cursor = Cursors.Cross;
            currentShapeType = Shape.Bitmap;
            isDrawing = true;
        }

        private void strokeWidths_SelectedIndexChanged(object sender, EventArgs e)
        {
            float f;
            if (float.TryParse(strokeWidths.Text as string, out f))
            {
                this.currentStrokeSize = f;
            }
        }

        private void traparencyList_SelectedIndexChanged(object sender, EventArgs e)
        {
            float f;
            if (float.TryParse(traparencyList.Text as string, out f))
            {
                this.currentTransparency = f;
            }
        }

        private void drawRoundRect_Click(object sender, EventArgs e)
        {
            if (isDrawing)
                return;

            this.Cursor = Cursors.Cross;
            currentShapeType = Shape.RoundedRectangle;
            isDrawing = true;

        }

        private void renderControl_MouseDown(object sender, MouseEventArgs e)
        {
            isDragging = true;

            if (!isDrawing)
                return;

            startPoint.X = e.X;
            startPoint.Y = e.Y;
            endPoint = startPoint;

            switch (currentShapeType)
            {
                case Shape.Line:
                    currentShape = new Line(this, startPoint, startPoint, currentStrokeSize, currentBrushIndex);
                    drawingShapes.Add(currentShape);
                    break;
                case Shape.Bitmap:
                    currentShape = new DrawingBitmap(
                            this,
                            new RectF(startPoint.X, startPoint.Y, startPoint.X, startPoint.Y),
                            currentBitmap, currentTransparency);
                    drawingShapes.Add(currentShape);
                    break;
                case Shape.RoundedRectangle:
                    currentShape = new RoundRectangle(this,
                            new RoundedRect(
                                new RectF(startPoint.X, startPoint.Y, startPoint.X, startPoint.Y),
                                20f, 20f),
                                currentStrokeSize,
                                currentBrushIndex, fill);
                    drawingShapes.Add(currentShape);
                    break;
                case Shape.Rectangle:
                    currentShape = new RectangleShape(this,
                                new RectF(startPoint.X, startPoint.Y, startPoint.X, startPoint.Y),
                                currentStrokeSize,
                                currentBrushIndex, fill);
                    drawingShapes.Add(currentShape);
                    break;
                case Shape.Ellipse:
                    currentShape = new EllipseShape(this,
                                new Ellipse(startPoint, 0, 0),
                                currentStrokeSize,
                                currentBrushIndex, fill);
                    drawingShapes.Add(currentShape);
                    break;
                case Shape.Text:
                    currentShape = new TextShape(this, currentTextLayout, startPoint,100,100,currentBrushIndex);
                    drawingShapes.Add(currentShape);
                    break;
            }
        }

        private void renderControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (!isDrawing || !isDragging)
                return;

            endPoint.X = e.X;
            endPoint.Y = e.Y;

            currentShape.EndPoint = endPoint;
            renderControl.Invalidate();
        }

        private void renderControl_MouseUp(object sender, MouseEventArgs e)
        {
            isDragging = false;
            isDrawing = false;
            currentShapeType = Shape.None;
            this.Cursor = Cursors.Arrow;
            renderControl.Invalidate();
        }

        private void clearButton_Click(object sender, EventArgs e)
        {
            currentShapeType = Shape.None;
            drawingShapes.Clear();
            currentShape = null;
            renderControl.Invalidate();
        }

        private void textButton_Click(object sender, EventArgs e)
        {
            if (isDrawing)
                return;

            TextDialog dialog = new TextDialog(this, 100, 100);
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                this.Cursor = Cursors.Cross;
                currentShapeType = Shape.Text;
                currentTextLayout = dialog.textLayout;
                isDrawing = true;
            }


        }

        private void RectButton_Click(object sender, EventArgs e)
        {
            if (isDrawing)
                return;

            this.Cursor = Cursors.Cross;
            currentShapeType = Shape.Rectangle;
            isDrawing = true;
        }

        private void ellipseButton_Click(object sender, EventArgs e)
        {
            if (isDrawing)
                return;

            this.Cursor = Cursors.Cross;
            currentShapeType = Shape.Ellipse;
            isDrawing = true;
        }

        private void fillButton_Click(object sender, EventArgs e)
        {
            fill = !fill;

        }


    }
}
